<?php

namespace App\Http\Controllers;

use App\Http\Traits\CacheTrait;
use App\Http\Traits\DeployTrait;
use App\Http\Traits\GitLabTrait;
use App\Models\RepoSetting;
use App\Models\Role;
use App\Models\User;
use Auth;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Collection;
use Log;
use Validator;

class DeployController extends Controller
{
    use CacheTrait, GitLabTrait, DeployTrait;

    public function loadDiff(Request $request, $project_id)
    {
        $repo_setting = RepoSetting::where('repo_id', $project_id)->first();

        if ($repo_setting->last_sha_id) {
            $current_sha_info = $this->getGitLab()->repositories->commit($project_id, $request->get('sha_id'));
            $last_sha_info    = $this->getGitLab()->repositories->commit($project_id, $repo_setting->last_sha_id);
            if (strtotime($current_sha_info['committed_date']) >= strtotime($last_sha_info['committed_date'])) {
                $from_sha_id = $last_sha_info['id'];
                $to_sha_id   = $current_sha_info['id'];
            } else {
                $from_sha_id = $current_sha_info['id'];
                $to_sha_id   = $last_sha_info['id'];
            }

            $compare_result = $this->getGitLab()->repositories->compare($project_id, $from_sha_id, $to_sha_id);

            return response($compare_result);
        } else {
            return response([]);
        }
    }

    public function projectBatch($project_id)
    {
        if (Auth::user()->hasRole(Role::OWNER)) {
            $setting_list = RepoSetting::where('repo_id', $project_id)->get();
        } else {
            return back()->with(['error_msg' => '只有管理员可以批量部署']);
        }

        return view('deploy.project_batch')->with(['list' => $setting_list]);
    }

    public function batch(Request $request)
    {
        $server_env  = $request->get('type', 'development');
        $existed_env = ['product', 'development', 'staging'];
        $server_env  = in_array($server_env, $existed_env, true) ? ucfirst($server_env) : 'Product';

        if (Auth::user()->hasRole(Role::OWNER)) {
            $setting_list = RepoSetting::where('server_env', $server_env)->get();
        } else {
            return back()->with(['error_msg' => '只有管理员可以批量部署']);
            /*$roles       = Auth::user()->roles;
            $setting_ids = [];
            foreach ($roles as $role) {
                $role_arr      = explode('_', $role->name);
                $setting_ids[] = end($role_arr);
            }
            $setting_list = RepoSetting::where(['id' => $setting_ids])->get();*/
        }

        return view('deploy.batch')->with(['list' => $setting_list]);
    }

    public function show($project_id)
    {
        $project      = $this->getProject($project_id);
        $setting_list = RepoSetting::where('repo_id', $project_id)->get();
        $branches     = $this->getBranches($project_id);
        $tags         = $this->getTags($project_id);

        usort($tags, function ($tag1, $tag2) {
            if (strtotime($tag1['commit']['created_at']) == strtotime($tag2['commit']['created_at'])) {
                return 0;
            }

            if (strtotime($tag1['commit']['created_at']) < strtotime($tag2['commit']['created_at'])) {
                return 1;
            }

            return -1;
        });
        $tags = array_splice($tags, 0, 10);
        /** @var User $user */
        $user                    = Auth::user();
        $has_permission_settings = new Collection();
        /** @var RepoSetting $item */
        foreach ($setting_list as $item) {
            $role_name = Role::getDeployRoleName($project_id, $item->id);
            if ($user->hasRole(Role::OWNER) || $user->hasRole($role_name) || $item->server_env == RepoSetting::SERVER_ENV_DEVELOPMENT) {
                $has_permission_settings->push($item);
            }
        }

        return view('deploy.show')->with([
            'project'      => $project,
            'setting_list' => $has_permission_settings,
            'tags'         => $tags,
            'branches'     => $branches,
        ]);
    }

    public function batchDeploy(Request $request)
    {
        if (Auth::user()->hasRole(Role::OWNER)) {
            foreach ($request->get('data') as $item) {
                $this->deployViaSettingId($item['setting_id'], $item['branch'], $item['checkout_sha']);
            }

            return response(['success_msg' => '已进入部署队列']);
        }

        return response(['error_msg' => '没有权限']);
    }

    public function webDeploy(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'project_id'   => 'required|integer',
            'setting_id'   => 'required|integer',
            'branch'       => 'required|string',
            'checkout_sha' => 'required|string',
        ]);

        if ($validator->fails()) {
            return back()->with('error_msg', '部署出了点小问题。');
        }

        /** @var User $user */
        $user      = Auth::user();
        $role_name = Role::getDeployRoleName($request->get('project_id'), $request->get('setting_id'));
        /** @var RepoSetting $setting */
        $setting = RepoSetting::find($request->get('setting_id'));
        if (!$user->hasRole(Role::OWNER) && !$user->hasRole($role_name) && ($setting->server_env != RepoSetting::SERVER_ENV_DEVELOPMENT)) {
            return back()->with('error_msg', '没有该项目部署权限');
        }

        $include_paths = $request->get('include_paths');

        if ($include_paths) {
            $exploded_paths = explode(PHP_EOL, $include_paths);
            foreach ($exploded_paths as $exploded_path) {
                $tree = $this->getGitLab()->repositories->tree($request->get('project_id'), ['path' => $exploded_path, 'ref_name' => $request->get('branch')]);
                if (!$tree) {
                    return back()->with('error_msg', '路径 ' . $exploded_path . ' 不存在')->withInput();
                }
            }
        }

        $return_msg = $this->deployViaSettingId($request->get('setting_id'), $request->get('branch'), $request->get('checkout_sha'), $include_paths);

        return back()->with(['success_msg' => $return_msg]);
    }

    public function hookDeploy(Request $request)
    {
        Log::info('request', [$request]);
        if (!$request->has('project')) {
            abort(Response::HTTP_FORBIDDEN, '缺少必要字段');
        }

        $request = $request->request->all();

        $this->deployViaWebHook($request['project_id'], $request['project']['path_with_namespace'], $request['user_name'], $request['checkout_sha'], $request['ref']);
    }
}
